

#include "CxType.h"
#include "CxTcpPort.h"
#include "CxIPService.h"

#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>

using namespace ImitateTansfer;


io_service	CxIPService::s_ioservice;
thread		*CxIPService::s_pwatchthread=NULL;

CxIPService::CxIPService(LPCSTR portname, vector<CxPort*>	*portgroup,
	UINT	portno,UINT	maxclient):m_portno(portno)	,
	m_acceptor(s_ioservice)	,	m_maxclient(maxclient)	,	m_pportgroup(portgroup)
{
	OpenPort(portname);

	if(s_pwatchthread==NULL)
	{
		s_pwatchthread=new thread(boost::bind<void>(&CxIPService::Watch_Handle,this));
	}	
}

CxIPService::~CxIPService()
{
	ClosePort();

	cout<<"~CxIPService() have been fini....."<<endl;
}

bool	CxIPService::OpenPort(LPCSTR portname)
{
	CX_ASSERT(portname);

	if(m_acceptor.is_open())ClosePort();

	try
	{
		m_addr=boost::asio::ip::address::from_string(portname);
		tcp::endpoint	_ep(m_addr,m_portno);
		
		m_acceptor.open(_ep.protocol());
		m_acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
		m_acceptor.bind(_ep);
		m_acceptor.listen();
	}

	catch(boost::system::system_error &e)
	{
		CX_ERR_MESSAGE(e.what());
	}



	CX_ASSERT(m_acceptor.is_open());
	CX_ASSERT(m_addr.is_v4() || m_addr.is_v6());

	return true;
}

bool	CxIPService::ClosePort()
{
    if(m_acceptor.is_open())
    {
        m_acceptor.cancel();
        m_acceptor.close();
    }
	CX_ASSERT(!m_acceptor.is_open());

	return true;
}



inline	bool	CxIPService::IsOpen()const
{
	return m_acceptor.is_open();
}


inline	void	CxIPService::Start()
{
	if(!m_acceptor.is_open())return ;

	CX_ASSERT(m_acceptor.is_open());
	tcp::socket *psock=new tcp::socket(s_ioservice);

	m_acceptor.async_accept(*psock,boost::bind<void>(&CxIPService::Accept_Handle_1,this,psock,
														boost::asio::placeholders::error));

}



void	CxIPService::Accept_Handle_1(CxIPService *_this,tcp::socket *psock,
									const boost::system::error_code &e)
{
	cout<<"Have Connect...."<<endl;

	_this->Start();
	char *buffer=new char[5];
	psock->async_read_some(boost::asio::buffer(buffer,3),
		boost::bind<void>(&CxIPService::Accept_Handle,_this,psock,buffer,
							boost::asio::placeholders::error));
}



void	CxIPService::Accept_Handle(CxIPService *_this,tcp::socket *psock,char *buffer
									,const boost::system::error_code &e)
{
	int number=0;

	if(buffer[0]==0x5f && buffer[1]==0x6f)
		number=buffer[2];

	else goto __FINIAL;
	try
	{
		if(number>_this->m_maxclient)goto __FINIAL;
		else 
		{
			if(_this->m_pportgroup->at(number)==NULL)
			{
				_this->m_pportgroup->at(number)=new CxTcpPort(psock);
			}
			else if(!_this->m_pportgroup->at(number)->IsOpen())
			{
				delete _this->m_pportgroup->at(number);
				_this->m_pportgroup->at(number)=new CxTcpPort(psock); 

			}
			else 
				goto __FINIAL;

			goto __SUCCESS;
		}
	}
	catch(boost::system::system_error &e)
	{
		CX_ERR_MESSAGE(e.what());
	}

__FINIAL:
	delete [] buffer;
	delete psock;
__SUCCESS:
	_this->sig_connected(number);
	return ;
}



void	CxIPService::Watch_Handle(CxIPService *_this)
{
	try
	{
		_this->Start();
		s_ioservice.run();
	}
	catch(boost::system::system_error &e)
	{
		CX_ERR_MESSAGE(e.what());
	}

	catch(boost::thread_interrupted &)
	{
	}
}


